#include <wx/brush.h>
#include "SoftJoy.h"


BEGIN_EVENT_TABLE(wxSoftJoy, wxScrolledWindow)
  EVT_SIZE    (wxSoftJoy::OnSize)
  EVT_MOUSE_EVENTS (wxSoftJoy::OnMouse)
  EVT_TIMER (wxID_ANY, wxSoftJoy::OnPosTimer)
  //EVT_ERASE_BACKGROUND(wxSoftJoy::OnEraseBackGround)
END_EVENT_TABLE()

DEFINE_EVENT_TYPE(wxEVT_SOFT_JOY_MOVE)
DEFINE_EVENT_TYPE(wxEVT_SOFT_JOY_BUTTON)



wxSoftJoy::wxSoftJoy(wxWindow *parent, const wxPoint& pos, const wxSize& size)
: wxScrolledWindow(parent,wxID_ANY,pos,size)
{
	this->SetBackgroundColour(*wxWHITE);
	m_Offset = wxPoint(0,-100);
	m_CursorColor = *wxGREEN;
	CentreCursor();
	m_Selected = false;

	m_VectX = 0;
	m_VectY = 0;
	m_MoveVectX = 0;
	m_MoveVectY = 0;

	m_BackMove = 0;
	m_Timer.SetOwner(GetEventHandler(),wxID_ANY);
	m_Timer.Start(100);
	

	InitImg();
}

wxSoftJoy::~wxSoftJoy(void)
{

}

void wxSoftJoy::CentreCursor(void)
{	
	m_Position = GetCenterPos();
}

void wxSoftJoy::InitImg(void)
{
	int s;
	s = CURSOR_RADIUS + CURSOR_BORDER;

	m_SelCurImg.Create(s*2,s*2);
	m_CurImg.Create(s*2,s*2);
	m_BGImg.Create(s*2,s*2);

	m_DCSelCurImg.SelectObject(m_SelCurImg);
	m_DCSelCurImg.SetBrush(*wxWHITE_BRUSH);
	m_DCSelCurImg.SetPen(*wxWHITE_PEN);
	m_DCSelCurImg.DrawRectangle(0,0,s*2,s*2);
	DrawCursor(m_DCSelCurImg,wxPoint(s,s),true);

	m_DCCurImg.SelectObject(m_CurImg);
	m_DCCurImg.SetBackground(*wxWHITE_BRUSH);
	m_DCCurImg.SetPen(*wxWHITE_PEN);
	m_DCCurImg.DrawRectangle(0,0,s*2,s*2);
	DrawCursor(m_DCCurImg,wxPoint(s,s),false);

	m_DCBGImg.SelectObject(m_BGImg);
}

void wxSoftJoy::DrawCurImage(wxDC &dst,wxDC &src,wxPoint &pos)
{
	int s = CURSOR_RADIUS + CURSOR_BORDER;
	dst.Blit(pos.x - s,pos.y - s,2*s,2*s,&src,0,0);
}

void wxSoftJoy::SaveCurImage(wxDC &dst,wxDC &src,wxPoint &pos)
{
	int s = CURSOR_RADIUS + CURSOR_BORDER;
	dst.Blit(0,0,2*s,2*s,&src,pos.x - s,pos.y - s);
}

wxPoint wxSoftJoy::GetCenterPos(void)
{
	wxPoint center;
	wxSize size = this->GetSize();
	 size = this->GetClientSize();
	center.x = (size.x + m_Offset.x)/2;
	center.y = (size.y + m_Offset.y)/2;
	return center;
}

wxPoint wxSoftJoy::Prescale(wxPoint pos)
{
	wxPoint prescal;
	wxSize size;
	size = this->GetSize();

	prescal.x = (unsigned short)pos.x * 0xFFFF / size.x;
	prescal.y = (unsigned short)pos.y * 0xFFFF / size.y;

	return prescal;
}

bool wxSoftJoy::IsOnCursor(wxPoint &point)
{
	wxRect rect = wxRect(
		m_Position - wxPoint(CURSOR_RADIUS,CURSOR_RADIUS),
		m_Position + wxPoint(CURSOR_RADIUS,CURSOR_RADIUS));

	return rect.Contains(point);
}

void wxSoftJoy::PostCursorChangeEvent(wxPoint &point)
{
	wxJoystickEvent joyEvent(wxEVT_SOFT_JOY_MOVE,GetId());
	joyEvent.SetPosition( Prescale(point + wxPoint(0,20)));
	joyEvent.SetEventObject(this);

	if(this->GetParent() != NULL)
	{
		//wxPostEvent(this->GetParent(), joyEvent);		
		GetEventHandler()->ProcessEvent(joyEvent);
	}
}

void wxSoftJoy::PostButtonChangeEvent(bool pressed)
{
	wxJoystickEvent joyEvent(wxEVT_SOFT_JOY_BUTTON,GetId());
	joyEvent.SetButtonChange(wxJOY_BUTTON1);
	joyEvent.SetButtonState((int)pressed);
	joyEvent.SetEventObject(this);
	wxPoint center;
	double len;

	if(this->GetParent() != NULL)
	{
		//wxPostEvent(this->GetParent(), joyEvent);
		GetEventHandler()->ProcessEvent(joyEvent);
	}

	if(pressed == 0)
	{
		center = GetCenterPos();
		m_VectX = (double)(center.x - m_Position.x);
		m_VectY = (double)(center.y - m_Position.y);
		len = sqrt((m_VectX*m_VectX) + (m_VectY*m_VectY));
		len /= BACK_STEPS;

		m_VectX/=len;
		m_VectY/=len;

		m_BackMove = 0;
		m_MoveVectX = m_Position.x;
		m_MoveVectY = m_Position.y;
	}
}

void wxSoftJoy::PostMouseMoveEvent(wxPoint &point)
{
	wxMouseEvent mouseEvent(wxEVT_MOTION);
	mouseEvent.m_x = point.x;
	mouseEvent.m_y = point.y;
	mouseEvent.m_metaDown = true;
	wxPostEvent(this, mouseEvent);
}

void wxSoftJoy::DrawMetricAxis(wxDC& dc)
{
	wxPoint px,py;
	wxSize size;

	size = this->GetSize();

	px.x = m_Offset.x;
	px.y = (size.y + m_Offset.y)/2;

	py.x = (size.x + m_Offset.x)/2;
	py.y = m_Offset.y;

	dc.SetPen(*wxGREY_PEN);
	dc.DrawLine(px,wxPoint(size.x,px.y));
	dc.DrawLine(py,wxPoint(py.x,size.y));
	
	SaveCurImage(m_DCBGImg,dc,GetCenterPos());
}

void wxSoftJoy::DrawCursor(wxDC &dc,wxPoint &pos,bool selected)
{
	dc.SetPen(*wxBLACK);

	if(selected)
	{
		dc.SetBrush(*wxRED_BRUSH);
		dc.DrawCircle(pos,CURSOR_RADIUS + CURSOR_BORDER);
	}

	dc.SetBrush(wxBrush(m_CursorColor));
	dc.DrawCircle(pos,CURSOR_RADIUS);
}

void wxSoftJoy::OnSize(wxSizeEvent& evt)
{	
	Refresh();
}

void  wxSoftJoy::OnMouse(wxMouseEvent& evt)
{
	bool refresh = false;
	wxPoint pos,old;
	pos = evt.GetPosition();
	old = m_Position;

	if(evt.GetEventType() == wxEVT_MOTION)
	{
		if(m_Position != pos)
		{
			if(m_Selected == true || evt.m_metaDown)
			{
				m_Position = pos;
				refresh = true;
				PostCursorChangeEvent(m_Position);
			}
		}
	}

	if(evt.IsButton())
	{
		bool prevButton = m_Selected;

		m_Selected = false;
		if(evt.LeftDown() && IsOnCursor(pos))
			m_Selected = true;

		if(prevButton != m_Selected)
		{
			PostButtonChangeEvent(m_Selected);
			pos = old;
			refresh = true;
		}
	}
	

	if(refresh)
	{
		wxClientDC dc(this);	
		DrawCurImage(dc,m_DCBGImg,old);
		SaveCurImage(m_DCBGImg,dc,pos);
		if(m_Selected)
			DrawCurImage(dc,m_DCSelCurImg,pos);
		else
			DrawCurImage(dc,m_DCCurImg,pos);
	}
}

void wxSoftJoy::OnDraw(wxDC& dc)
{
	/*m_VectX = 0;
	m_VectY = 0;
	m_MoveVectX = 0;
	m_MoveVectY = 0;
	m_BackMove = 0;*/

	CentreCursor();
	DrawMetricAxis(dc);
	DrawCursor(dc,GetCenterPos(),m_Selected);
}

void wxSoftJoy::OnPosTimer(wxTimerEvent &evt)
{
	wxPoint center;
	if(m_Selected == 0)
	{
		center = GetCenterPos();
		if(m_Position != center)
		{
			m_MoveVectX += m_VectX * m_BackMove;
			m_MoveVectY += m_VectY * m_BackMove;

			wxPoint newpos;

			newpos.x = (int)m_MoveVectX;
			newpos.y = (int)m_MoveVectY;			

			if(m_BackMove < MAX_MOVE_BACK)
				m_BackMove ++;

			if(abs((double) m_MoveVectX - center.x) < EPS &&  
				abs((double) m_MoveVectY - center.y) < EPS)
				newpos = center;

			PostCursorChangeEvent(newpos);
			PostMouseMoveEvent(newpos);
		}
	}
}